package com.pdool.game.core.msg;

import com.pdool.common.constants.Constant;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.socket.WebSocketSession;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 玩家消息队列
 */
public class UserMsgQueue implements Runnable {
    private static final byte NONE = 0;
    private static final byte QUEUED = 1;
    private static final byte RUNNING = 2;
    private final WebSocketSession session;
    private final ReentrantLock lock = new ReentrantLock();
    private volatile byte state = NONE;

    ThreadPoolTaskExecutor logicPool;

    private final LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();

    public UserMsgQueue(WebSocketSession session, ThreadPoolTaskExecutor logicPool) {
        this.session = session;
        this.logicPool = logicPool;
    }

    /**
     * 加入队列
     *
     * @param t
     */
    public final void addQueue(Runnable t) {
        if (queue.size() >= Constant.USER_MAX_MSG_QUEUE_NUM) {
            return;
        }
        queue.add(t);
        execute();
    }

    protected final Runnable removeFirst() {
        return queue.remove();
    }

    protected final void removeAndExecuteFirst() {
        //当前会话为空或关闭就不处理已经放在线程池的处理器
        if (session == null || !session.isOpen()) {
            this.clear();
            return;
        }
        logicPool.execute(removeFirst());
    }

    protected final void clear() {
        queue.clear();
    }

    @Override
    public final void run() {
        try {
            while (!isEmpty()) {
                setState(QUEUED, RUNNING);
                try {
                    while (!isEmpty()) {
                        removeAndExecuteFirst();
                    }
                } finally {
                    setState(RUNNING, QUEUED);
                }
            }
        } finally {
            setState(QUEUED, NONE);
        }
    }


    protected final boolean isEmpty() {
        return queue.isEmpty();
    }

    private final void lock() {
        lock.lock();
    }

    private final void unlock() {
        lock.unlock();
    }

    protected final void execute() {
        lock();
        try {
            if (state != NONE) {
                return;
            }
            state = QUEUED;
        } finally {
            unlock();
        }
        // 放入队列线程池中处理
        logicPool.execute(this);
    }

    private void setState(byte expected, byte value) {
        lock();
        try {
            if (state != expected) {
                throw new IllegalStateException("state: " + state + ", expected: " + expected);
            }
        } finally {
            state = value;
            unlock();
        }
    }

}
